//+------------------------------------------------------------------+
//| 邮件发送辅助函数                                                    |
//+------------------------------------------------------------------+
void SendFormattedEmail(string subject, string message_type, datetime bar_time, double bar_close)
{
    // 获取时区偏移量（分钟）并格式化为字符串
    int offset_minutes = TimeGMTOffset() / 60;
    int offset_hours = offset_minutes / 60;
    string timezone_str = "GMT" + (offset_hours >= 0 ? "+" : "") + IntegerToString(offset_hours);

    // 格式化邮件正文
    string full_body = message_type;
    // 使用 TIME_DATE | TIME_SECONDS 格式化时间，使其包含年月日时分秒
    full_body += "时间: " + TimeToString(bar_time, TIME_DATE|TIME_SECONDS) + " (" + timezone_str + ")\n";
    full_body += "货币对: " + Symbol() + "\n";
    full_body += "图表周期: " + EnumToString(_Period) + "\n";
    full_body += "收盘价: " + DoubleToString(bar_close, _Digits); 
    
    // 发送邮件并打印日志
    // 注意: 请确保在MT5客户端的 \"工具 -> 选项 -> 电邮\" 中已正确配置邮箱设置
    SendMail(subject, full_body);
    Print("邮件已发送: ", subject, " - ", full_body);
}

//+------------------------------------------------------------------+
//| 检查信号并发送邮件的函数                                            |
//+------------------------------------------------------------------+
void CheckAndSendEmail(int i, const datetime &time[], const double &close[])
{
    // 统一的邮件主题
    string subject = "[" + Symbol() + ", " + EnumToString(_Period) + "] 主图指标信号";
    string message_body;

    // --- 条件1: 红色线 上穿 趋势线 --- (已禁用邮件通知)
    /*
    if (RedLineBuffer[i-1] <= TrendLineBuffer[i-1] && RedLineBuffer[i] > TrendLineBuffer[i])
    {
        message_body = "信号类型: 红线上穿趋势线\n";
        SendFormattedEmail(subject, message_body, time[i], close[i]);
    }
    */

    // --- 条件2: 绿线 下穿 趋势线 --- (已禁用邮件通知)
    /*
    if (GreenLineBuffer[i-1] >= TrendLineBuffer[i-1] && GreenLineBuffer[i] < TrendLineBuffer[i])
    {
        message_body = "信号类型: 绿线下穿趋势线\n";
        SendFormattedEmail(subject, message_body, time[i], close[i]);
    }
    */

    // --- 条件3: VAR11下穿0, 且近期无'多'/'空'信号 --- (已禁用邮件通知)
    /*
    if (VAR11Buffer[i-1] >= 0 && VAR11Buffer[i] < 0)
    {
        bool signalFound = false;
        // 向前回溯检查指定数量的K线
        for (int k = 1; k <= InpNoSignalBars; k++)
        {
            int bar_to_check = i - k;
            if (bar_to_check < 0) break; // 防止索引越界
            
            // 检查是否存在"多"或"空"的图表对象
            if (ObjectFind(0, "多_" + IntegerToString(bar_to_check)) >= 0 || ObjectFind(0, "空_" + IntegerToString(bar_to_check)) >= 0)
            {
                signalFound = true;
                break;
            }
         }
        
        // 如果在指定范围内没有找到信号，则发送邮件
        if (!signalFound)
        {
            message_body = "信号类型: VAR11下穿0 (近" + IntegerToString(InpNoSignalBars) + "根K线无'多'/'空'信号)\n";
            SendFormattedEmail(subject, message_body, time[i], close[i]);
        }
    }
    */

    // --- 条件4: 上一根K线（即当前已收盘的这根K线i）出现"多"和"空"字 --- (已禁用邮件通知)
    /*
    // 重新计算触发'多'/'空'标签的条件
    bool cross_tmp_up = (prevTMPBuffer[i] <= 0 && TMPBuffer[i] > 0);
    bool cross_tmp_down = (prevTMPBuffer[i] >= 0 && TMPBuffer[i] < 0);

    // 检查'空'信号条件
    if (cross_tmp_up && RedLineBuffer[i] > TrendLineBuffer[i])
    {
        message_body = "信号类型: K线收盘出现'空'信号\n";
        SendFormattedEmail(subject, message_body, time[i], close[i]);
    }
    
    // 检查'多'信号条件
    if (cross_tmp_down && GreenLineBuffer[i] < TrendLineBuffer[i])
    {
        message_body = "信号类型: K线收盘出现'多'信号\n";
        SendFormattedEmail(subject, message_body, time[i], close[i]);
    }
    */
}

//+------------------------------------------------------------------+
   //|                                                           m1.mql5 |
   //|                        Copyright 2024, MetaQuotes Software Corp. |
   //|                                             https://www.mql5.com |
   //+------------------------------------------------------------------+
   #property copyright "Copyright 2024, MetaQuotes Software Corp."
   #property link      "https://www.mql5.com"
   #property version   "1.00"
   //主图indicator_chart_window  副图 indicator_separate_window
   #property indicator_chart_window
   #property indicator_buffers 19
#property indicator_plots   10

// 枚举类型定义
enum ENUM_INPUT_YES_NO
{
   INPUT_YES = 1, // Yes
   INPUT_NO = 0   // No
};

//--- input parameters
input int InpNoSignalBars = 20; // 检查无信号的K线数量

// Peak-Valley 参数
input int FilterCandle = 25; // Peak-Valley过滤K线数量
input ENUM_INPUT_YES_NO InpUseFilter = INPUT_NO;   // 使用趋势检测过滤
input ENUM_INPUT_YES_NO InpUseAlert = INPUT_YES;   // PV弹窗警报
input ENUM_INPUT_YES_NO InpSendMail = INPUT_YES;   // PV邮件通知
input ENUM_INPUT_YES_NO InpSendPush = INPUT_YES;   // 发送推送通知
input double PVOffsetPoints = 5.0; //(PV信号计算显示位置偏移点数 (推荐: 外汇10-30, 黄金50-150, 指数20-80)
input ENUM_INPUT_YES_NO PVUseATR = INPUT_YES; //(PV信号计算显示位置) ATR动态偏移
input double PVATRMultiplier = 0.2; //(计算显示位置PV信号) ATR倍数 (0.1-1.0)

// 神龙通道参数
input int DragonQual = 8;  // 神龙通道质量参数
input int DragonLen = 18;   // 神龙通道长度参数
input ENUM_INPUT_YES_NO DragonAlert = INPUT_YES;     // 神龙弹窗警报
input ENUM_INPUT_YES_NO DragonMail = INPUT_YES;     // 神龙邮件通知
input double DragonOffsetPoints = 10.0; //(计算显示位置)神龙通道箭头偏移点数 (推荐: 外汇5-20, 黄金30-100, 指数10-50)
input ENUM_INPUT_YES_NO DragonUseATR = INPUT_YES; //(计算显示位置) 使用ATR动态偏移
input int DragonATRPeriod = 14; //(计算显示位置) ATR周期
input double DragonATRMultiplier = 0.3; //(计算显示位置神龙信号) ATR倍数 (0.1-1.0)

// 文字显示控制参数
input ENUM_INPUT_YES_NO ShowTopBottomText = INPUT_NO; // 显示"H""L"文字
input ENUM_INPUT_YES_NO ShowBSSignals = INPUT_NO; // 显示B和S信号

// 麦语言均线参数
input ENUM_INPUT_YES_NO ShowMAFill = INPUT_YES; // 显示均线填充区域
input color MAFillUpColor = 0x10000050;     // MA填充上涨颜色(MA5>EMA144)
input color MAFillDownColor = 0x10005000;   // MA填充下跌颜色(MA5<EMA144)

// K线颜色设置参数
input ENUM_INPUT_YES_NO EnableCandleColors = INPUT_YES; // 启用K线颜色设置
input color UpCandleColor = clrRed;        // 上涨K线颜色
input color DownCandleColor = clrGreen;    // 下跌K线颜色
input color DojiFlatColor = clrGreen;      // 平盘K线颜色

   //--- plot MA5和EMA144填充区域 (移到第一个，确保在最底层)
#property indicator_label1 "MA填充区域上涨"
#property indicator_type1  DRAW_FILLING
#property indicator_color1 clrNONE,clrNONE
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

//--- plot 红线
#property indicator_label2  "红线"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrMagenta
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

//--- plot 绿线
#property indicator_label3  "绿线"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrLightSeaGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

//--- plot 趋势线
#property indicator_label4  "趋势线"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrGold
#property indicator_style4  STYLE_SOLID
#property indicator_width4  3

//--- plot Peak-Valley上箭头
#property indicator_label5  "Peak-Valley上箭头"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrRed
#property indicator_style5  STYLE_SOLID
#property indicator_width5  2

//--- plot Peak-Valley下箭头
#property indicator_label6  "Peak-Valley下箭头"
#property indicator_type6   DRAW_ARROW
#property indicator_color6  clrBlue
#property indicator_style6  STYLE_SOLID
#property indicator_width6  2

//--- plot 神龙通道上箭头
#property indicator_label7  "神龙通道上箭头"
#property indicator_type7   DRAW_ARROW
#property indicator_color7  clrMagenta
#property indicator_style7  STYLE_SOLID
#property indicator_width7  2

//--- plot 神龙通道下箭头
#property indicator_label8  "神龙通道下箭头"
#property indicator_type8   DRAW_ARROW
#property indicator_color8  clrDeepSkyBlue
#property indicator_style8  STYLE_SOLID
#property indicator_width8  2

//--- plot MA5线（隐藏线条，只用于填充计算）
#property indicator_label9  "MA5"
#property indicator_type9   DRAW_LINE
#property indicator_color9  clrNONE
#property indicator_style9  STYLE_SOLID
#property indicator_width9  1

//--- plot EMA144线（隐藏线条，只用于填充计算）
#property indicator_label10  "EMA144"
#property indicator_type10   DRAW_LINE
#property indicator_color10  clrNONE
#property indicator_style10  STYLE_SOLID
#property indicator_width10  1

   //--- indicator buffers
   double RedLineBuffer[];
   double GreenLineBuffer[];
   double TrendLineBuffer[];
   double OscillationFilterBuffer[];
   double X0Buffer[];  // 计算用，不显示
   double TMPBuffer[]; // 计算用，不显示
   double prevTMPBuffer[]; // 用于CROSS检测
   double prevX0Buffer[];  // 用于CROSS检测
   double VAR11Buffer[]; // VAR11指标缓冲区
   double ROC10Buffer[]; // VAR11的中间计算值
   double PeakValleyUpBuffer[];   // Peak-Valley上箭头缓冲区
   double PeakValleyDownBuffer[]; // Peak-Valley下箭头缓冲区
   double DragonUpBuffer[];       // 神龙通道上箭头缓冲区
   double DragonDownBuffer[];     // 神龙通道下箭头缓冲区
   double DragonTrendBuffer[];    // 神龙通道趋势缓冲区（计算用）
   double MA5Buffer[];            // MA5缓冲区
   double EMA144Buffer[];         // EMA144缓冲区
   double MAFillBuffer1[];        // MA填充区域缓冲区1（上边界）
   double MAFillBuffer2[];        // MA填充区域缓冲区2（下边界）

   //--- global variables
   double HH999[];
   double LL999[];
   double H1[];
   double L1[];
   double X0[];
   double X00[];
   double H2[];
   double L2[];
   double K1[];
   double K2[];
   double X000[];
   double TMP[];
   double VAR1[];
   double VAR2[];
   double VAR3[];
   double HH88[];
   double LL88[];
   double H18[];
   double L18[];
   double H28[];
   double L28[];
   double K18[];
   double K28[];
   double TMP1[];
   double oscillationFilter[];
   
   //--- 神龙通道全局变量
   int dragon_bindex;  // 神龙通道上涨计数器
   int dragon_sindex;  // 神龙通道下跌计数器
   
   //--- 初始化保护变量
   static bool first_run_complete = false; // 标记第一次运行是否完成

   //--- MA handles
   int ma43_handle;
   int ma98_handle;
   int ma200_handle;
   int ma5_handle;     // MA5句柄
   int ema144_handle;  // EMA144句柄
   
   //--- ATR handle for dragon channel
   int atr_handle;

   //+------------------------------------------------------------------+
   //| Custom indicator initialization function                         |
   //+------------------------------------------------------------------+
   int OnInit()
   {
   //--- indicator buffers mapping
   SetIndexBuffer(0, MAFillBuffer1, INDICATOR_DATA);        // MA填充区域缓冲区1 (第1个plot)
   SetIndexBuffer(1, MAFillBuffer2, INDICATOR_DATA);        // MA填充区域缓冲区2 (第2个plot)
   SetIndexBuffer(2, RedLineBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, GreenLineBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, TrendLineBuffer, INDICATOR_DATA);
   SetIndexBuffer(5, PeakValleyUpBuffer, INDICATOR_DATA);   // Peak-Valley上箭头 (第5个plot)
   SetIndexBuffer(6, PeakValleyDownBuffer, INDICATOR_DATA); // Peak-Valley下箭头 (第6个plot)
   SetIndexBuffer(7, DragonUpBuffer, INDICATOR_DATA);       // 神龙通道上箭头 (第7个plot)
   SetIndexBuffer(8, DragonDownBuffer, INDICATOR_DATA);     // 神龙通道下箭头 (第8个plot)
   SetIndexBuffer(9, MA5Buffer, INDICATOR_DATA);            // MA5线 (第9个plot)
   SetIndexBuffer(10, EMA144Buffer, INDICATOR_DATA);         // EMA144线 (第10个plot)
   SetIndexBuffer(11, OscillationFilterBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(12, X0Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(13, TMPBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(14, prevTMPBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(15, prevX0Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(16, VAR11Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(17, ROC10Buffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(18, DragonTrendBuffer, INDICATOR_CALCULATIONS);

   // 设置MA填充区域属性 (第1个plot，索引为0)
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   
   // 设置MA填充区域绘制在背景层，避免遮挡K线
   // 注意：DRAW_FILLING在#property中已设置，这里不需要重复设置PLOT_DRAW_TYPE
   PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_SOLID);
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 1);
   PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 1);
   
   // 设置MA填充区域的颜色（使用用户输入的颜色参数）
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, MAFillUpColor);   // 上涨颜色(MA5>EMA144)
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, MAFillDownColor); // 下跌颜色(MA5<EMA144)
   
   // 强制设置填充区域在最底层
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_FILLING);
   PlotIndexSetInteger(0, PLOT_SHIFT, 0);
   
   // 设置Peak-Valley箭头属性
   PlotIndexSetInteger(4, PLOT_ARROW, 233);  // 上箭头 (对应第5个plot)
   PlotIndexSetInteger(5, PLOT_ARROW, 234);  // 下箭头 (对应第6个plot)
   PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   
   // 设置Peak-Valley箭头的绘制起始位置
   PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, 200);
   PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, 200);
   
   // 设置Peak-Valley缓冲区为时间序列模式（与原始指标保持一致）
   ArraySetAsSeries(PeakValleyUpBuffer, true);
   ArraySetAsSeries(PeakValleyDownBuffer, true);
   
   // 设置神龙通道箭头属性
   PlotIndexSetInteger(6, PLOT_ARROW, 233);  // 神龙通道上箭头 (对应第7个plot)
   PlotIndexSetInteger(7, PLOT_ARROW, 234);  // 神龙通道下箭头 (对应第8个plot)
   PlotIndexSetDouble(6, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(7, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   
   // 设置神龙通道箭头的绘制起始位置
   PlotIndexSetInteger(6, PLOT_DRAW_BEGIN, 20);
   PlotIndexSetInteger(7, PLOT_DRAW_BEGIN, 20);
   
   // 设置神龙通道缓冲区为正常模式（不使用时间序列）
   ArraySetAsSeries(DragonUpBuffer, false);
   ArraySetAsSeries(DragonDownBuffer, false);
   
   // 初始化神龙通道计数器
   dragon_bindex = 0;
   dragon_sindex = 0;

//--- set precision
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);

//--- sets first bar from what index will be drawn
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 200);  // MA填充区域
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 200);  // MA填充区域
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, 200);  // 红线
   PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, 200);  // 绿线
   PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, 200);  // 趋势线

   //--- create MA handles
      ma43_handle = iMA(NULL, 0, 43, 0, MODE_EMA, PRICE_CLOSE);
      ma98_handle = iMA(NULL, 0, 98, 0, MODE_EMA, PRICE_CLOSE);
      ma200_handle = iMA(NULL, 0, 200, 0, MODE_SMA, PRICE_CLOSE);
      ma5_handle = iMA(NULL, 0, 5, 0, MODE_SMA, PRICE_CLOSE);          // MA5默认周期为5
      ema144_handle = iMA(NULL, 0, 144, 0, MODE_EMA, PRICE_CLOSE);    // EMA144默认周期为144
      
      //--- create ATR handle for dragon channel
      atr_handle = iATR(NULL, 0, DragonATRPeriod);
      
      if(ma43_handle == INVALID_HANDLE || ma98_handle == INVALID_HANDLE || ma200_handle == INVALID_HANDLE || 
         ma5_handle == INVALID_HANDLE || ema144_handle == INVALID_HANDLE || atr_handle == INVALID_HANDLE)
      {
         Print("Failed to create MA or ATR handles");
         return(INIT_FAILED);
      }
      
      // 初始化K线颜色设置
      if(EnableCandleColors == INPUT_YES)
      {
         // 获取图表背景色用于空心效果
         // color bg_color = (color)ChartGetInteger(0, CHART_COLOR_BACKGROUND);
         // 透明色
         color bg_color = clrNONE; 
         // 设置上涨K线为红色边框空心效果
         // 方法：将实体填充设为背景色，边框设为红色
         ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, bg_color);         // 上涨K线实体填充颜色（背景色，实现空心效果）
         ChartSetInteger(0, CHART_COLOR_CHART_UP, UpCandleColor);       // 上涨K线边框和影线颜色（使用配置颜色）
         
         // 设置下跌K线为绿色实心效果  
         ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, DownCandleColor);   // 下跌K线实体填充颜色（绿色实心）
         ChartSetInteger(0, CHART_COLOR_CHART_DOWN, DownCandleColor);    // 下跌K线边框和影线颜色（绿色）
         
         // 设置平盘K线颜色和去除中间竖线
         ChartSetInteger(0, CHART_COLOR_CHART_LINE, clrNONE);           // 去除K线实体中间的竖线（设为透明）
         
         // 设置为蜡烛图模式
         ChartSetInteger(0, CHART_MODE, CHART_CANDLES);
         
         // 确保K线在前景层
         ChartSetInteger(0, CHART_FOREGROUND, true);                     
      }

      return(INIT_SUCCEEDED);
   }

   //+------------------------------------------------------------------+
   //| Custom indicator iteration function                              |
   //+------------------------------------------------------------------+
   int OnCalculate(const int rates_total,
                  const int prev_calculated,
                  const datetime &time[],
                  const double &open[],
                  const double &high[],
                  const double &low[],
                  const double &close[],
                  const long &tick_volume[],
                  const long &volume[],
                  const int &spread[])
   {
      if(rates_total < 200) return(0);
      
      //--- resize arrays
      ArrayResize(HH999, rates_total);
      ArrayResize(LL999, rates_total);
      ArrayResize(H1, rates_total);
      ArrayResize(L1, rates_total);
      ArrayResize(X0, rates_total);
      ArrayResize(X00, rates_total);
      ArrayResize(H2, rates_total);
      ArrayResize(L2, rates_total);
      ArrayResize(K1, rates_total);
      ArrayResize(K2, rates_total);
      ArrayResize(X000, rates_total);
      ArrayResize(TMP, rates_total);
      ArrayResize(VAR1, rates_total);
      ArrayResize(VAR2, rates_total);
      ArrayResize(VAR3, rates_total);
      ArrayResize(HH88, rates_total);
      ArrayResize(LL88, rates_total);
      ArrayResize(H18, rates_total);
      ArrayResize(L18, rates_total);
      ArrayResize(H28, rates_total);
      ArrayResize(L28, rates_total);
      ArrayResize(K18, rates_total);
      ArrayResize(K28, rates_total);
      ArrayResize(TMP1, rates_total);
      ArrayResize(oscillationFilter, rates_total);
      ArrayResize(VAR11Buffer, rates_total);
      ArrayResize(ROC10Buffer, rates_total);
      ArrayResize(PeakValleyUpBuffer, rates_total);
      ArrayResize(PeakValleyDownBuffer, rates_total);
      ArrayResize(DragonUpBuffer, rates_total);
      ArrayResize(DragonDownBuffer, rates_total);
      ArrayResize(DragonTrendBuffer, rates_total);
      ArrayResize(MA5Buffer, rates_total);
      ArrayResize(EMA144Buffer, rates_total);
      ArrayResize(MAFillBuffer1, rates_total);
      ArrayResize(MAFillBuffer2, rates_total);
      
      // --- get MA and ATR data
      double ma43_data[], ma98_data[], ma200_data[], ma5_data[], ema144_data[], atr_data[];
      ArrayResize(ma43_data, rates_total);
      ArrayResize(ma98_data, rates_total);
      ArrayResize(ma200_data, rates_total);
      ArrayResize(ma5_data, rates_total);
      ArrayResize(ema144_data, rates_total);
      ArrayResize(atr_data, rates_total);
      
      if(CopyBuffer(ma43_handle, 0, 0, rates_total, ma43_data) <= 0 ||
         CopyBuffer(ma98_handle, 0, 0, rates_total, ma98_data) <= 0 ||
         CopyBuffer(ma200_handle, 0, 0, rates_total, ma200_data) <= 0 ||
         CopyBuffer(ma5_handle, 0, 0, rates_total, ma5_data) <= 0 ||
         CopyBuffer(ema144_handle, 0, 0, rates_total, ema144_data) <= 0 ||
         CopyBuffer(atr_handle, 0, 0, rates_total, atr_data) <= 0)
      {
         return(0);
      }
      
      int limit = prev_calculated == 0 ? 200 : prev_calculated - 1;
      
      // 神龙通道计算起始位置
      int dragon_start = 20;
      if(prev_calculated > 0) 
         dragon_start = prev_calculated - 1;
      
      
      // ========== 神龙通道计数器逻辑修正 ==========
      // 使用静态变量记录上次信号触发的位置，避免重复计算
      static int last_signal_bar = -1;
      static bool signal_triggered = false;
      static datetime last_dragon_up_time = 0;   // 神龙通道上箭头最后报警时间
      static datetime last_dragon_down_time = 0; // 神龙通道下箭头最后报警时间
      static int last_dragon_up_bar = -1;        // 神龙通道上箭头最后报警K线索引
      static int last_dragon_down_bar = -1;      // 神龙通道下箭头最后报警K线索引
      static bool dragon_first_run = true;       // 标记是否是首次运行
      static int dragon_init_call_count = 0;     // 记录初始化调用次数
      
      // 记录初始化调用次数
      if(prev_calculated == 0)
      {
         dragon_init_call_count++;
         Print("[神龙通道] 初始化调用次数: ", dragon_init_call_count);
      }
      
      // 只在新K线时重新计算计数器
      if(prev_calculated == 0 || rates_total > prev_calculated + 1)
      {
         dragon_sindex = 0; // 重置下跌计数器
         dragon_bindex = 0; // 重置上涨计数器
         signal_triggered = false;
         last_signal_bar = -1;
         
         // 首次初始化时重置报警记录
         if(prev_calculated == 0 && dragon_init_call_count == 1)
         {
            last_dragon_up_time = 0;
            last_dragon_down_time = 0;
            last_dragon_up_bar = -1;
            last_dragon_down_bar = -1;
         }
         
         // 从dragon_start开始重新计算累积计数
         for(int j = dragon_start; j < rates_total; j++)
         {
            if(j >= 4) // 确保有足够的历史数据进行比较
            {
               // 价格趋势判断：比较当前收盘价与4根K线前的收盘价
               bool price_up = close[j] > close[j-4];     // 当前价格高于4根K线前 -> 上涨趋势
               bool price_down = close[j] < close[j-4];   // 当前价格低于4根K线前 -> 下跌趋势
               
               // 累积计数逻辑
               if(price_up)
               {
                  dragon_bindex += 1;
               }
               if(price_down)
               {
                  dragon_sindex += 1;
               }
            }
         }
         
         // 输出当前累积计数状态（仅在调试时）
         Print("[神龙通道] 重新计算累积计数: dragon_bindex=", dragon_bindex, ", dragon_sindex=", dragon_sindex, ", DragonQual=", DragonQual);
      }
      
      for(int i = limit; i < rates_total; i++)
      {
         
         // ========== 神龙通道计算逻辑 ==========
         // 神龙通道是一个基于价格趋势反转的箭头信号指标
         // 核心思想：统计连续上涨/下跌次数，当达到阈值且满足特定条件时产生反转信号
         // 基于原始神龙通道指标逻辑实现
         if(i >= dragon_start)
         {
            
            // ========== 第二步：初始化缓冲区 ==========
            // 初始化神龙通道箭头缓冲区为空值
            DragonUpBuffer[i] = EMPTY_VALUE;      // 上涨箭头缓冲区
            DragonDownBuffer[i] = EMPTY_VALUE;    // 下跌箭头缓冲区
            DragonTrendBuffer[i] = close[i];      // 趋势缓冲区（用于计算，存储当前收盘价）
         
            // ========== 第三步：计算箭头显示位置的智能偏移量 ==========
            // 智能偏移量用于确定箭头在图表上的显示位置
            // 可以选择ATR动态偏移或固定点数偏移
            double smart_offset;
            if(DragonUseATR == INPUT_YES && i >= DragonATRPeriod)
            {
               // 使用ATR动态偏移：根据市场波动性自动调整箭头位置
               // ATR值 * 倍数，确保最小偏移为3个点
               // ATR越大，市场波动越大，箭头偏移也越大，避免与价格重叠
               smart_offset = MathMax(atr_data[i] * DragonATRMultiplier, _Point * 3);
            }
            else
            {
               // 使用固定点数偏移：固定的点数偏移量
               // 适用于波动性相对稳定的市场或用户偏好固定偏移的情况
               smart_offset = _Point * DragonOffsetPoints;
            }
            
            // ========== 第四步：下跌信号判断与触发 ==========
            // 下跌信号触发条件（五个条件必须同时满足）：
            // 1. dragon_bindex > DragonQual：连续上涨次数超过质量阈值（表明已有足够的上涨动能，准备回调）
            // 2. close[i] < open[i]：当前K线为阴线（价格开始回落的确认信号）
            // 3. high[i] >= iHigh(...)：当前最高价达到或超过DragonLen周期内的最高点（触及阻力位）
            // 4. i < rates_total - 1：确保K线已收盘（不是当前正在形成的K线）
            // 5. 防止重复信号：确保不在同一K线上重复触发信号
            // 注意：原始指标使用 rates_total-1-(i-1) = rates_total-i 来计算iHighest的shift参数
            // 这个计算方式是为了从当前位置向前回看DragonLen个周期 比如 20 个周期 
            // dragon_bindex 统计连续上涨的次数
            // DragonQual 连续上涨的次数超过质量阈值（表明已有足够的上涨动能，准备回调）
            if((dragon_bindex > DragonQual) && (close[i] < open[i]) && 
               (high[i] >= iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, DragonLen, rates_total-1-(i-1)))) &&
               (i < rates_total - 1))  // 确保K线已收盘
            {
               // 详细信号触发日志
               Print("[神龙通道] *** 下跌信号触发 *** K线[", i, "] dragon_bindex=", dragon_bindex, ", DragonQual=", DragonQual);
               Print("[神龙通道] 触发条件: close[", i, "]=", close[i], " < open[", i, "]=", open[i], ", high[", i, "]=", high[i]);
               Print("[神龙通道] K线收盘确认: i=", i, " < rates_total-1=", rates_total-1, " (K线已收盘)");
               Print("[神龙通道] 信号位置: high[", i, "]=", high[i], ", 偏移=", smart_offset, ", 箭头位置=", high[i] + smart_offset);
               Print("[神龙通道] 设置下跌箭头: DragonDownBuffer[", i, "] = ", high[i] + smart_offset);
               
               // 记录信号触发状态，防止重复信号
               signal_triggered = true;
               last_signal_bar = i;
               
               // 在最高价上方显示下跌箭头（加上偏移量避免与价格重叠）
               DragonDownBuffer[i] = high[i] + smart_offset;
               
               // ========== 警报和通知逻辑 ==========
               // 确定警报基于的K线位置
               int whichBar = i;  // 默认基于前一根K线
               // if (DragonCurrentBar == INPUT_YES) whichBar = i;  // 可选择基于当前K线
               
               // 只对最新的几根K线触发警报，避免历史数据弹窗
               // 只有当信号出现在最近3根K线内时才触发警报
               // 第一次加载时（prev_calculated == 0）也允许最近的信号报警
               bool isRecentSignal = (i >= rates_total - 3);
               
               // 使用K线时间和索引双重防止重复报警
               datetime signal_time = time[i];
               // 检查冷却期：信号触发后至少3根K线内不再触发
               bool inCooldown = false;
               if(last_dragon_down_bar >= 0 && i - last_dragon_down_bar < 3)
               {
                  inCooldown = true;
               }
               
               // 调试信息
               Print("[神龙通道-下] 检查报警条件: i=", i, ", rates_total=", rates_total, ", isRecentSignal=", isRecentSignal, 
                     ", signal_time=", TimeToString(signal_time), ", last_dragon_down_time=", TimeToString(last_dragon_down_time),
                     ", last_dragon_down_bar=", last_dragon_down_bar, ", inCooldown=", inCooldown, 
                     ", prev_calculated=", prev_calculated, ", dragon_init_call_count=", dragon_init_call_count);
               
               // 首次运行时需要特殊处理，避免重复报警
               bool shouldAlert = false;
               if(prev_calculated == 0 && dragon_init_call_count <= 2)
               {
                  // 初始化阶段，只在第一次调用且是最新信号时报警
                  shouldAlert = isRecentSignal && !inCooldown && (i == rates_total - 2) && (dragon_init_call_count == 1);
               }
               else
               {
                  // 非首次运行，正常检查
                  shouldAlert = isRecentSignal && !inCooldown && last_dragon_down_time != signal_time;
               }
               
               if (shouldAlert)
               {
                  Print("[神龙通道-下] 满足报警条件，准备发送报警");
                  
                  // 弹窗警报
                  if (DragonAlert == INPUT_YES)
                  {
                     string alert_message = Symbol() + ", " + TimeframeToString(Period()) + ": Reverse:Arrow down " + TimeToString(signal_time);
                     Alert(alert_message);
                     Print("[神龙通道] 发送警报: ", alert_message);
                  }
                  
                  // 邮件通知
                  if (DragonMail == INPUT_YES && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED))
                  {
                     SendFormattedEmail(" Reverse:Arrow down", "信号类型:  Reverse:Arrow down\n", time[i], close[i]);
                     Print("[神龙通道] 发送邮件: Reverse:Arrow down");
                  }
                  
                  // 更新最后报警时间和索引
                  last_dragon_down_time = signal_time;
                  last_dragon_down_bar = i;
               }
            }
            
            // ========== 第五步：上涨信号判断与触发 ==========
            // 上涨信号触发条件（五个条件必须同时满足）：
            // 1. dragon_sindex > DragonQual：连续下跌次数超过质量阈值（表明已有足够的下跌动能，准备反弹）
            // 2. close[i] > open[i]：当前K线为阳线（价格开始反弹的确认信号）
            // 3. low[i] <= iLow(...)：当前最低价达到或低于DragonLen周期内的最低点（触及支撑位）
            // 4. i < rates_total - 1：确保K线已收盘（不是当前正在形成的K线）
            // 5. 防止重复信号：确保不在同一K线上重复触发信号
            // 注意：原始指标使用 rates_total-1-(i-1) = rates_total-i 来计算iLowest的shift参数
            // 这个计算方式是为了从当前位置向前回看DragonLen个周期
            if((dragon_sindex > DragonQual) && (close[i] > open[i]) && 
               (low[i] <= iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, DragonLen, rates_total-1-(i-1)))) &&
               (i < rates_total - 1))  // 确保K线已收盘
            {
               // 详细信号触发日志
               Print("[神龙通道] *** 上涨信号触发 *** K线[", i, "] dragon_sindex=", dragon_sindex, ", DragonQual=", DragonQual);
               Print("[神龙通道] 触发条件: close[", i, "]=", close[i], " > open[", i, "]=", open[i], ", low[", i, "]=", low[i]);
               Print("[神龙通道] K线收盘确认: i=", i, " < rates_total-1=", rates_total-1, " (K线已收盘)");
               Print("[神龙通道] 信号位置: low[", i, "]=", low[i], ", 偏移=", smart_offset, ", 箭头位置=", low[i] - smart_offset);
               Print("[神龙通道] 设置上涨箭头: DragonUpBuffer[", i, "] = ", low[i] - smart_offset);
               
               // 记录信号触发状态，防止重复信号
               signal_triggered = true;
               last_signal_bar = i;
               
               // 在最低价下方显示上涨箭头（减去偏移量避免与价格重叠）
               DragonUpBuffer[i] = low[i] - smart_offset;
               
               // ========== 警报和通知逻辑 ==========
               // 确定警报基于的K线位置
               int whichBar = i;  // 默认基于前一根K线
               // if (DragonCurrentBar == INPUT_YES) whichBar = i;  // 可选择基于当前K线
       
               // 只对最新的几根K线触发警报，避免历史数据弹窗
               // 只有当信号出现在最近3根K线内时才触发警报
               // 第一次加载时（prev_calculated == 0）也允许最近的信号报警
               bool isRecentSignal = (i >= rates_total - 3);
               
               // 使用K线时间和索引双重防止重复报警
               datetime signal_time = time[i];
               // 检查冷却期：信号触发后至少3根K线内不再触发
               bool inCooldown = false;
               if(last_dragon_up_bar >= 0 && i - last_dragon_up_bar < 3)
               {
                  inCooldown = true;
               }
               
               // 调试信息
               Print("[神龙通道-上] 检查报警条件: i=", i, ", rates_total=", rates_total, ", isRecentSignal=", isRecentSignal, 
                     ", signal_time=", TimeToString(signal_time), ", last_dragon_up_time=", TimeToString(last_dragon_up_time),
                     ", last_dragon_up_bar=", last_dragon_up_bar, ", inCooldown=", inCooldown, 
                     ", prev_calculated=", prev_calculated, ", dragon_init_call_count=", dragon_init_call_count);
               
               // 首次运行时需要特殊处理，避免重复报警
               bool shouldAlert = false;
               if(prev_calculated == 0 && dragon_init_call_count <= 2)
               {
                  // 初始化阶段，只在第一次调用且是最新信号时报警
                  shouldAlert = isRecentSignal && !inCooldown && (i == rates_total - 2) && (dragon_init_call_count == 1);
               }
               else
               {
                  // 非首次运行，正常检查
                  shouldAlert = isRecentSignal && !inCooldown && last_dragon_up_time != signal_time;
               }
               
               if (shouldAlert)
               {
                  Print("[神龙通道-上] 满足报警条件，准备发送报警");
                  
                  // 弹窗警报
                  if (DragonAlert == INPUT_YES)
                  {
                     string alert_message = Symbol() + ", " + TimeframeToString(Period()) + ": Reverse:Arrow up " + TimeToString(signal_time);
                     Print("[神龙通道] 发送警报: ", alert_message); 
                     Alert(alert_message);
                  }
                  
                  // 邮件通知
                  if (DragonMail == INPUT_YES && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED))
                  {
                     SendFormattedEmail("Reverse:Arrow up", "信号类型: Reverse:Arrow up\n", time[i], close[i]);
                     Print("[神龙通道] 发送邮件: Reverse:Arrow up");
                  }
                  
                  // 更新最后报警时间和索引
                  last_dragon_up_time = signal_time;
                  last_dragon_up_bar = i;
               }
            }
         }

         // ========== 神龙通道计算逻辑结束 ==========


         // 计算HH999和LL999
         double hh999 = HHV(high, i, 1)/10 + HHV(high, i, 2)/10 + HHV(high, i, 2)/10 + 
                        HHV(high, i, 4)/10 + HHV(high, i, 4)/10 + HHV(high, i, 8)/10 + 
                        HHV(high, i, 8)/10 + HHV(high, i, 13)/10 + HHV(high, i, 40)/10 + HHV(high, i, 20)/10;
         
         double ll999 = LLV(low, i, 1)/10 + LLV(low, i, 2)/10 + LLV(low, i, 2)/10 + 
                        LLV(low, i, 4)/10 + LLV(low, i, 4)/10 + LLV(low, i, 8)/10 + 
                        LLV(low, i, 8)/10 + LLV(low, i, 13)/10 + LLV(low, i, 40)/10 + LLV(low, i, 20)/10;
         
         // 计算H1和L1
         double h1 = 0, l1 = 0;
         if(i >= 2)
         {
            double prev_hh999 = HH999[i-1];
            double prev_ll999 = LL999[i-1];
            double prev2_hh999 = HH999[i-2];
            double prev2_ll999 = LL999[i-2];
            
            if(hh999 < prev_hh999 && ll999 < prev_ll999 && open[i-1] > close[i-1] && 
               open[i] > close[i] && (open[i] - close[i]) > 0)
            {
               h1 = prev2_hh999;
            }
            
            if(ll999 > prev_ll999 && hh999 > prev_hh999 && open[i-1] < close[i-1] && 
               open[i] < close[i] && (close[i] - open[i]) > 0)
            {
               l1 = prev2_ll999;
            }
         }
         
         // 存储计算结果
         HH999[i] = hh999;
         LL999[i] = ll999;
         H1[i] = h1;
         L1[i] = l1;
         X0[i] = h1;
         X00[i] = l1;
         
         // 计算H2和L2 (VALUEWHEN逻辑)
         double h2 = i > 0 ? H2[i-1] : 0;
         double l2 = i > 0 ? L2[i-1] : 0;
         
         if(X0[i] > 0) h2 = X0[i];
         if(X00[i] > 0) l2 = X00[i];
         
         H2[i] = h2;
         L2[i] = l2;
         
         // 计算K1和K2
         double k1 = 0;
         if(close[i] > h2) k1 = -3;
         else if(close[i] < l2) k1 = 1;
         
         K1[i] = k1;
         
         double k2 = i > 0 ? K2[i-1] : 0;
         if(k1 != 0) k2 = k1;
         K2[i] = k2;
         
         X000[i] = k2;
         TMP[i] = k2;
         
         // 计算EMA和趋势线
         double var1 = ma43_data[i];
         double var2 = ma98_data[i];
         
         VAR1[i] = var1;
         VAR2[i] = var2;
         
         // 红线计算
         double redLine = (close[i] - var1) * 2 / (13 + 1) + var1;
         RedLineBuffer[i] = redLine;
         
         // VAR3计算
         double var3 = (close[i] - var2) * 2 / (54 + 1) + var2;
         VAR3[i] = var3;
         
         // 绿线计算：IF(红线>VAR3,VAR3,红线)
         // 当红线>趋势线时，绿线=趋势线；否则绿线=红线
         double greenLine = redLine > var3 ? var3 : redLine;
         GreenLineBuffer[i] = greenLine;
         
         // 趋势线
         TrendLineBuffer[i] = var3;
         
         // 震荡过滤线
         double oscillationFilterValue = ma200_data[i];
         OscillationFilterBuffer[i] = oscillationFilterValue;
         oscillationFilter[i] = oscillationFilterValue;
         
         // 计算HH88和LL88
         double hh88 = HHV(high, i, 1)/5 + HHV(high, i, 2)/5 + HHV(high, i, 2)/5 + 
                     HHV(high, i, 5)/5 + HHV(high, i, 8)/5;
         double ll88 = LLV(low, i, 1)/5 + LLV(low, i, 2)/5 + LLV(low, i, 2)/5 + 
                     LLV(low, i, 5)/5 + LLV(low, i, 8)/5;
         
         HH88[i] = hh88;
         LL88[i] = ll88;
         
         // 计算H18和L18
         double h18 = 0, l18 = 0;
         if(i >= 2)
         {
            if(high[i] < high[i-2] && high[i-1] < high[i-2])
               h18 = high[i-2];
            if(low[i] > low[i-2] && low[i-1] > low[i-2])
               l18 = low[i-2];
         }
         
         H18[i] = h18;
         L18[i] = l18;
         
         // 计算H28和L28 (VALUEWHEN逻辑)
         double h28 = i > 0 ? H28[i-1] : 0;
         double l28 = i > 0 ? L28[i-1] : 0;
         
         if(h18 > 0) h28 = h18;
         if(l18 > 0) l28 = l18;
         
         H28[i] = h28;
         L28[i] = l28;
         
         // 计算K18和K28
         double k18 = 0;
         if(close[i] > h28) k18 = -3;
         else if(close[i] < l28) k18 = 1;
         
         K18[i] = k18;
         
         double k28 = i > 0 ? K28[i-1] : 0;
         if(k18 != 0) k28 = k18;
         K28[i] = k28;
         
         TMP1[i] = k28;
         
         X0Buffer[i] = X0[i];
         TMPBuffer[i] = TMP[i];
         
         // ========== 麦语言均线计算 ==========
         // 计算MA5和EMA144
         MA5Buffer[i] = ma5_data[i];
         EMA144Buffer[i] = ema144_data[i];
         
         // ========== 麦语言填充区域绘制 ==========
         // 使用DRAW_FILLING方式绘制MA5和EMA144之间的填充区域
         if(ShowMAFill == INPUT_YES && i > 0)  // 确保有足够的数据
         {
            // 设置填充区域的上下边界
            MAFillBuffer1[i] = MA5Buffer[i];
            MAFillBuffer2[i] = EMA144Buffer[i];
         }
         else
         {
            // 如果不显示填充，设置为空值
            MAFillBuffer1[i] = EMPTY_VALUE;
            MAFillBuffer2[i] = EMPTY_VALUE;
         }
         
         // 保存当前值用于下次CROSS检测
      prevTMPBuffer[i] = (i > 0) ? TMPBuffer[i-1] : TMPBuffer[i];
      prevX0Buffer[i] = (i > 0) ? X0Buffer[i-1] : X0Buffer[i];
      
      // 添加调试输出（仅显示最新几个值）
         if (i >= rates_total - 3) {
               // Print("Bar ", i, ": 红线=", RedLineBuffer[i], ", 绿线=", GreenLineBuffer[i], 
               //       ", 趋势线=", TrendLineBuffer[i], ", 震荡过滤线=", OscillationFilterBuffer[i]);
               // Print("Bar ", i, ": X0=", X0Buffer[i], ", TMP=", TMPBuffer[i]);
         }
         
         // 绘制文本标签 - 对于实时K线（最后一根），需要特殊处理
         // 只有在K线收盘或者不是当前实时K线时才绘制文字标签
         bool isCurrentBar = (i == rates_total - 1);
         bool isHistoricalBar = !isCurrentBar;
         
         // 计算VAR11
         // 1. 计算 (CLOSE-REF(CLOSE,10))/REF(CLOSE,10)*1000
         ROC10Buffer[i] = (i >= 10 && close[i-10] != 0) ? (close[i] - close[i-10]) / close[i-10] * 1000 : 0;
         
         // 2. 计算EMA(..., 10)
         double alpha = 2.0 / (10 + 1.0); // EMA平滑系数
         if(i > 0)
            VAR11Buffer[i] = ROC10Buffer[i] * alpha + VAR11Buffer[i-1] * (1 - alpha);
         else
            VAR11Buffer[i] = ROC10Buffer[i];

         // Peak-Valley 箭头计算 - 使用与原始代码相同的逻辑
         // 注意：这里需要在主循环结束后单独处理Peak-Valley逻辑

         // 历史K线直接绘制，实时K线也绘制但会在函数内部处理删除逻辑
         DrawTextLabels(i, time, open, close, high, low, redLine, greenLine, var3, oscillationFilterValue, hh999, ll999, hh88, ll88, isCurrentBar);
         
         // 在主循环结束后记录神龙通道最终计数器状态（仅最新K线）
         if(i == rates_total - 1)
         {
            // Print("[神龙通道] 主循环结束 - 最终计数器状态: dragon_bindex=", dragon_bindex, ", dragon_sindex=", dragon_sindex);
            // Print("[神龙通道] 最新K线收盘[", i, "] 价格信息: open=", open[i], ", high=", high[i], ", low=", low[i], ", close=", close[i]);
            if(i >= 4)
            {
               // Print("[神龙通道] 价格比较: close[", i, "]=", close[i], " vs close[", i-4, "]=", close[i-4], ", 差值=", close[i] - close[i-4]);
               bool price_up = close[i] > close[i-4];
               bool price_down = close[i] < close[i-4];
               // Print("[神龙通道] 价格趋势: 上涨=", price_up, ", 下跌=", price_down);
            }
         }
      }
      
      // Peak-Valley 箭头计算 - 采用综合指标12的简化逻辑
      // 注意：Peak-Valley使用时间序列模式（ArraySetAsSeries = true），索引0为最新K线
      ArraySetAsSeries(low, true);
      ArraySetAsSeries(high, true);
      
      // 使用简化的时间戳防重复机制（参考综合指标12）
      static datetime last_time = 0;
      static datetime last_pv_up_time = 0;    // PV上箭头最后报警时间
      static datetime last_pv_down_time = 0;  // PV下箭头最后报警时间
      
      // 重新加载指标时重置时间戳，确保新信号能够正常报警
      if(prev_calculated == 0)
      {
         last_time = 0;
         last_pv_up_time = 0;
         last_pv_down_time = 0;
         Print("[Peak-Valley] 指标重新加载，重置报警时间戳");
      }
      
      // 修复PV计算范围逻辑，确保重新加载与实时计算的一致性
      // 对于Peak-Valley指标，我们需要始终计算足够的历史数据以确保信号准确性
      int pv_limit;
      if(prev_calculated > 0)
      {
         // 实时运行时：绝对不重新计算已确定的历史信号
         // 只计算最新的1-2根K线，这样可以完全避免历史信号偏移
         pv_limit = 1;  // 只检查最新的2根K线(i=0,1)
      }
      else
      {
         // 初始化时计算所有K线
         pv_limit = rates_total - 1;
      }
      
      for(int i = pv_limit; i >= 0; i--)
      {
         // 严格的信号保护：实时运行时绝对不清除任何历史信号
         // 只在初始化时清除所有信号
         if(prev_calculated == 0)
         {
            PeakValleyUpBuffer[i] = EMPTY_VALUE;
            PeakValleyDownBuffer[i] = EMPTY_VALUE;
         }
         // 实时运行时，只清除正在重新计算的最新K线
         else if(i <= 1)
         {
            PeakValleyUpBuffer[i] = EMPTY_VALUE;
            PeakValleyDownBuffer[i] = EMPTY_VALUE;
         }
         
         // 修复：使用原始算法的边界检查条件
         // 原始代码使用 if(i+FilterCandle+2<rates_total)
         if(i + FilterCandle + 2 < rates_total)
         {
            // === 红色上箭头条件检查 ===
            // 1. 满足Peak-Valley的isUp条件
            // 2. 添加趋势线过滤：红线 > 趋势线
            if(isUp(i+1, high, low, close, rates_total))
            {
               // 将时间序列索引转换为正常索引以访问趋势线数据
               // Peak-Valley索引i+1对应的正常索引为：rates_total - 1 - (i+1)
               int normal_index = rates_total - 1 - (i+1);
               
               // 确保索引有效且添加趋势线过滤条件
               if(normal_index >= 0 && normal_index < rates_total)
               {
                  // 趋势线过滤条件：红线 > 趋势线时才显示红色上箭头
                  if(RedLineBuffer[normal_index] > TrendLineBuffer[normal_index])
                  {
                     // 计算PV信号智能偏移量：优先使用ATR动态偏移，否则使用固定点数
                     double pv_offset;
                     if(PVUseATR == INPUT_YES && normal_index >= DragonATRPeriod)
                     {
                        // 使用ATR动态偏移：ATR值 * PV专用倍数，确保最小偏移
                        pv_offset = MathMax(atr_data[normal_index] * PVATRMultiplier, _Point * 5);
                     }
                     else
                     {
                        // 使用固定点数偏移
                        pv_offset = _Point * PVOffsetPoints;
                     }
                     
                     // 修复：使用原始算法的信号位置和数据访问方式
                     // 原始代码使用 bufferUp[i+2] = low[i+2]
                     PeakValleyUpBuffer[i+1] = iLow(Symbol(), 0, i+1) - pv_offset;
                     
                     // 修复报警逻辑：信号设置和报警完全同步
                     // 信号设置在i+1位置，所以报警也应该基于i+1位置
                     // 当i==0时，i+1=1，表示为位置1的K线设置信号并报警
                     // 在初始化时（prev_calculated == 0）不触发报警
                     // 确保第一次运行完成后才开始报警
                     if(i == 0 && first_run_complete)  
                     {
                        // 检查信号设置位置的K线时间，确保同步
                        datetime signal_time = iTime(Symbol(), 0, i+1);
                        if(last_pv_up_time != signal_time)  // 确保该K线未报警过
                        {
                           // Peak-Valley上箭头信号 (红线>趋势线)
                           Print("[Peak-Valley] 检测到上箭头信号，K线索引: ", i+1, " 时间: ", TimeToString(signal_time));
                           string message = Symbol() + ", " + TimeframeToString(Period()) + ": Peak-Valley: Arrow up " + TimeToString(signal_time);
                           if(InpUseAlert) {
                              Print(message); 
                              Alert(message);
                           } 
                           if(InpSendMail && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED)) SendFormattedEmail("Peak-Valley: Arrow up", "信号类型: Peak-Valley: Arrow up\n", signal_time, iClose(Symbol(), 0, i+1));
                           if(InpSendPush && TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED)) SendNotification(message);
                           last_pv_up_time = signal_time;
                        }
                     }
                  }
                  // 如果红线<=趋势线，则不显示箭头（保持EMPTY_VALUE）
               }
            }
            
            // === 蓝色下箭头条件检查 ===
            // 1. 满足Peak-Valley的isDown条件
            // 2. 添加趋势线过滤：绿线 < 趋势线
            if(isDown(i+1, high, low, close, rates_total))
            {
               // 将时间序列索引转换为正常索引以访问趋势线数据
               int normal_index = rates_total - 1 - (i+1);
               
               // 确保索引有效且添加趋势线过滤条件
               if(normal_index >= 0 && normal_index < rates_total)
               {
                  // 趋势线过滤条件：绿线 < 趋势线时才显示蓝色下箭头
                  if(GreenLineBuffer[normal_index] < TrendLineBuffer[normal_index])
                  {
                     // 计算PV信号智能偏移量：优先使用ATR动态偏移，否则使用固定点数
                     double pv_offset;
                     if(PVUseATR == INPUT_YES && normal_index >= DragonATRPeriod)
                     {
                        // 使用ATR动态偏移：ATR值 * PV专用倍数，确保最小偏移
                        pv_offset = MathMax(atr_data[normal_index] * PVATRMultiplier, _Point * 5);
                     }
                     else
                     {
                        // 使用固定点数偏移
                        pv_offset = _Point * PVOffsetPoints;
                     }
                     
                     // 修复：使用原始算法的信号位置和数据访问方式
                     // 原始代码使用 bufferD1own[i+2] = high[i+2]
                     PeakValleyDownBuffer[i+1] = iHigh(Symbol(), 0, i+1) + pv_offset;
                     
                     // 修复报警逻辑：信号设置和报警完全同步
                     // 信号设置在i+1位置，所以报警也应该基于i+1位置
                     // 当i==0时，i+1=1，表示为位置1的K线设置信号并报警
                     // 在初始化时（prev_calculated == 0）不触发报警
                     // 确保第一次运行完成后才开始报警
                     if(i == 0 && first_run_complete)  
                     {
                        // 检查信号设置位置的K线时间，确保同步
                        datetime signal_time = iTime(Symbol(), 0, i+1);
                        if(last_pv_down_time != signal_time)  // 确保该K线未报警过
                        {
                           //Peak-Valley下箭头信号 (绿线<趋势线)
                           Print("[Peak-Valley] 检测到下箭头信号，K线索引: ", i+1, " 时间: ", TimeToString(signal_time));
                           string message = Symbol() + ", " + TimeframeToString(Period()) + ": Peak-Valley: Arrow down " + TimeToString(signal_time); 
                           if(InpUseAlert){
                              Print(message);
                              Alert(message);
                           } 
                           if(InpSendMail && TerminalInfoInteger(TERMINAL_EMAIL_ENABLED)) SendFormattedEmail("Peak-Valley: Arrow down", "信号类型: Peak-Valley: Arrow down\n", signal_time, iClose(Symbol(), 0, i+1));
                           if(InpSendPush && TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED)) SendNotification(message); 
                           last_pv_down_time = signal_time;
                        }
                     }
                  }
                  // 如果绿线>=趋势线，则不显示箭头（保持EMPTY_VALUE）
               }
            }
         }
      }
      
      // --- 邮件通知逻辑 ---
      // 只在新的K线形成时检查一次，避免重复发送
      static datetime last_checked_bar_time = 0;
      int check_bar_index = rates_total - 2; // 检查最新关闭的K线

      // 如果图表历史记录足够，并且最新关闭的K线时间与上次检查的时间不同，则进行检查
      if(check_bar_index > 0 && time[check_bar_index] > last_checked_bar_time)
      {
          CheckAndSendEmail(check_bar_index, time, close);
          last_checked_bar_time = time[check_bar_index]; // 更新上次检查的K线时间
      }
      
      // 验证神龙通道箭头缓冲区状态（调试用）
      int arrow_count = 0;
      for(int i = 0; i < rates_total; i++)
      {
         if(DragonUpBuffer[i] != EMPTY_VALUE) arrow_count++;
         if(DragonDownBuffer[i] != EMPTY_VALUE) arrow_count++;
      }
      if(arrow_count > 0)
      {
         // Print("[神龙通道] 缓冲区验证: 共发现 ", arrow_count, " 个箭头信号在缓冲区中");
      }
      
      // K线颜色设置功能
      if(EnableCandleColors == INPUT_YES)
      {
         SetCandleColors(rates_total, open, close);
      }
      
      // 标记第一次运行完成
      // 只有在第一次OnCalculate返回后的下一次调用才设置为true
      if(!first_run_complete && prev_calculated > 0)
      {
         first_run_complete = true;
         Print("指标初始化完成，开始监控新信号");
      }
      
      // 标记神龙通道首次运行完成
      if(dragon_first_run)
      {
         dragon_first_run = false;
         Print("[神龙通道] 首次运行完成，切换到正常报警模式");
      }
      
      return(rates_total);
   }

   //+------------------------------------------------------------------+
   //| 绘制文本标签函数                                                    |
   //+------------------------------------------------------------------+
   void DrawTextLabels(int i, const datetime &time[], const double &open[], const double &close[], 
                     const double &high[], const double &low[], double redLine, double greenLine, 
                     double trendLine, double oscillationFilterVal, double hh999, double ll999, 
                     double hh88, double ll88, bool isCurrentBar = false)
   {
      // 确保有前一个值可用于比较
      if(i == 0) return;
      
      // 如果是当前K线（实时数据），先删除之前可能创建的文字标签
      // 避免实时数据变化时出现错误的文字显示
      if(isCurrentBar)
      {
         string objNames[] = {"空_" + IntegerToString(i), "多_" + IntegerToString(i), 
                             "顶1_" + IntegerToString(i), "底1_" + IntegerToString(i),
                             "顶2_" + IntegerToString(i), "底2_" + IntegerToString(i)};
         
         // 删除当前K线上可能存在的所有文字标签
         for(int j = 0; j < ArraySize(objNames); j++)
         {
            if(ObjectFind(0, objNames[j]) >= 0)
            {
               ObjectDelete(0, objNames[j]);
               // 添加调试信息
               if(i >= ArraySize(time) - 3)
                  Print("删除实时K线文字标签: ", objNames[j]);
            }
         }
      }
      
      // CROSS(TMP,0) 检测 - TMP从下方穿越0
      bool crossTMP0 = (prevTMPBuffer[i] <= 0 && TMPBuffer[i] > 0);
      // CROSS(0,TMP) 检测 - TMP从上方穿越0
      bool cross0TMP = (prevTMPBuffer[i] >= 0 && TMPBuffer[i] < 0);
      
      // CROSS(X0,0) 检测 - X0从下方穿越0
      bool crossX00 = (prevX0Buffer[i] <= 0 && X0Buffer[i] > 0);
      // CROSS(0,X0) 检测 - X0从上方穿越0
      bool cross0X0 = (prevX0Buffer[i] >= 0 && X0Buffer[i] < 0);
      
      string objName;
      
      // 第一组文本标签 - 只有满足条件才创建
      // 对于实时K线，添加额外的稳定性检查
      bool shouldCreateLabel = !isCurrentBar; // 历史K线直接创建
      
      if(crossTMP0 && redLine > trendLine)
      {
         if(ShowBSSignals == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "空_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh999))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "S");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 12);
                  
                  // 添加调试信息
                  if(i >= ArraySize(time) - 3)
                     Print("创建空标签在K线: ", i, ", 红线=", redLine, ", 趋势线=", trendLine);
               }
            }
            else if(isCurrentBar)
            {
               // 实时K线满足条件时创建临时标签
               objName = "空_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh999))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "S?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow); // 用黄色表示临时状态
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }
      }
      
      if(cross0TMP && greenLine < trendLine)
      {
         if(ShowBSSignals == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "多_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll999))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "B");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 12);
                  
                  // 添加调试信息
                  if(i >= ArraySize(time) - 3)
                     Print("创建多标签在K线: ", i, ", 绿线=", greenLine, ", 趋势线=", trendLine);
               }
            }
            else if(isCurrentBar)
            {
               // 实时K线满足条件时创建临时标签
               objName = "多_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll999))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "B?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow); // 用黄色表示临时状态
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }
      }
      
      // 第二组文本标签 - 使用TMP1的交叉检测
      bool crossTMP10 = (i > 0 && TMP1[i-1] <= 0 && TMP1[i] > 0);
      bool cross0TMP1 = (i > 0 && TMP1[i-1] >= 0 && TMP1[i] < 0);
      
      if(crossTMP10 && close[i] < oscillationFilter[i] && greenLine < trendLine && 
         (greenLine - open[i])/greenLine * 10000 < 3)
      {
         if(ShowTopBottomText == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "顶1_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "H");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
               }
            }
            else if(isCurrentBar)
            {
               objName = "顶1_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "H?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }
      }
      
      if(cross0TMP1 && close[i] > oscillationFilter[i] && redLine > trendLine && 
         (open[i] - redLine)/redLine * 10000 < 3)
      {
         if(ShowTopBottomText == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "底1_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "L");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
               }
            }
            else if(isCurrentBar)
            {
               objName = "底1_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "L?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }
      }
      
      if(crossTMP10 && close[i] > oscillationFilter[i] && greenLine < trendLine && 
         (greenLine - open[i])/greenLine * 10000 < 3)
      {
         if(ShowTopBottomText == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "顶2_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "H");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
               }
            }
            else if(isCurrentBar)
            {
               objName = "顶2_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], hh88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "H?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }
      }
      
      if(cross0TMP1 && close[i] < oscillationFilter[i] && redLine > trendLine && 
         (open[i] - redLine)/redLine * 10000 < 3)
      {
         if(ShowTopBottomText == INPUT_YES)
         {
            if(shouldCreateLabel)
            {
               objName = "底2_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "L");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
               }
            }
            else if(isCurrentBar)
            {
               objName = "底2_" + IntegerToString(i);
               if(ObjectCreate(0, objName, OBJ_TEXT, 0, time[i], ll88))
               {
                  ObjectSetString(0, objName, OBJPROP_TEXT, "L?");
                  ObjectSetInteger(0, objName, OBJPROP_COLOR, clrYellow);
                  ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_UPPER);
                  ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
               }
            }
         }  
      }
   }

   //+------------------------------------------------------------------+
   //| HHV函数 - 获取指定周期内的最高价                                      |
   //+------------------------------------------------------------------+
   double HHV(const double &array[], int index, int period)
   {
      if(index < period - 1) return array[index];
      
      double maxVal = array[index];
      for(int i = 1; i < period; i++)
      {
         if(index - i >= 0 && array[index - i] > maxVal)
            maxVal = array[index - i];
      }
      return maxVal;
   }

   //+------------------------------------------------------------------+
   //| LLV函数 - 获取指定周期内的最低价                                      |
   //+------------------------------------------------------------------+
   double LLV(const double &array[], int index, int period)
   {
      if(index < period - 1) return array[index];
      
      double minVal = array[index];
      for(int i = 1; i < period; i++)
      {
      if(index - i >= 0 && array[index - i] < minVal)
            minVal = array[index - i];
      }
      return minVal;
   }

   //+------------------------------------------------------------------+
   //| Peak-Valley isUp函数                                              |
   //+------------------------------------------------------------------+
   bool isUp(int index, const double &high[], const double &low[], const double &close[], int rates_total)
   {
      bool flag=true;
      int preIndex=index+1;
      
      // 使用原始算法：直接使用iLow/iHigh/iClose函数，避免数组索引问题
      if(
         iLow(Symbol(), 0, index) > iLow(Symbol(), 0, preIndex)
         && iHigh(Symbol(), 0, index) > iHigh(Symbol(), 0, preIndex)
         && iClose(Symbol(), 0, index) > iClose(Symbol(), 0, preIndex)
      )
        {
         int startIndex=preIndex+1;
         int endIndex=preIndex+FilterCandle-1;
         
         // 使用原始算法的数据访问方式
         for(int i=startIndex; i<=endIndex; i++)
           {
            if(iLow(Symbol(), 0, i) < iLow(Symbol(), 0, preIndex))
              {
               flag=false;
               break;
              }
           }
        }
      else
        {
         flag=false;
        }

      return flag;
   }

   //+------------------------------------------------------------------+
   //| Peak-Valley isDown函数                                            |
   //+------------------------------------------------------------------+
   bool isDown(int index, const double &high[], const double &low[], const double &close[], int rates_total)
   {
      bool flag=true;
      int preIndex=index+1;
      
      // 使用原始算法：直接使用iLow/iHigh/iClose函数，避免数组索引问题
      if(
         iLow(Symbol(), 0, index) < iLow(Symbol(), 0, preIndex)
         && iHigh(Symbol(), 0, index) < iHigh(Symbol(), 0, preIndex)
         && iClose(Symbol(), 0, index) < iClose(Symbol(), 0, preIndex)
      )
        {
      int start=preIndex+1;
      int end=preIndex+FilterCandle-1;
      
      // 使用原始算法的数据访问方式
      for(int i=start; i<=end; i++)
        {
         if(iHigh(Symbol(), 0, i) > iHigh(Symbol(), 0, preIndex))
           {
            flag=false;
            break;
           }
        }
     }
   else
     {
      flag=false;
     }

   return flag;
  }

   //+------------------------------------------------------------------+
   //| 静态Peak-Valley isUp函数 - 不依赖于rates_total的动态变化          |
   //+------------------------------------------------------------------+
   bool isStaticUp(int index, const double &high[], const double &low[], const double &close[])
   {
      // 基本条件检查
      int preIndex = index - 1;
      if(preIndex < 0 || index < 0) return false;
      
      // 价格上升条件
      if(low[index] > low[preIndex] && high[index] > high[preIndex] && close[index] > close[preIndex])
      {
         // 向前检查FilterCandle根K线，确保preIndex是局部最低点
         int startCheck = preIndex - FilterCandle + 1;
         if(startCheck < 0) startCheck = 0;
         
         for(int i = startCheck; i <= preIndex - 1; i++)
         {
            if(low[i] < low[preIndex])
            {
               return false;  // 发现更低的点，不是局部最低
            }
         }
         return true;
      }
      return false;
   }

   //+------------------------------------------------------------------+
   //| 静态Peak-Valley isDown函数 - 不依赖于rates_total的动态变化        |
   //+------------------------------------------------------------------+
   bool isStaticDown(int index, const double &high[], const double &low[], const double &close[])
   {
      // 基本条件检查
      int preIndex = index - 1;
      if(preIndex < 0 || index < 0) return false;
      
      // 价格下降条件
      if(low[index] < low[preIndex] && high[index] < high[preIndex] && close[index] < close[preIndex])
      {
         // 向前检查FilterCandle根K线，确保preIndex是局部最高点
         int startCheck = preIndex - FilterCandle + 1;
         if(startCheck < 0) startCheck = 0;
         
         for(int i = startCheck; i <= preIndex - 1; i++)
         {
            if(high[i] > high[preIndex])
            {
               return false;  // 发现更高的点，不是局部最高
            }
         }
         return true;
      }
      return false;
   }

   //+------------------------------------------------------------------+
   //| Timeframe to string                                              |
   //+------------------------------------------------------------------+
   string TimeframeToString(const ENUM_TIMEFRAMES timeframe)
   {
      return StringSubstr(EnumToString(timeframe), 7);
   }

   //+------------------------------------------------------------------+
   //| 指标去初始化函数                                                    |
   //+------------------------------------------------------------------+
   //| K线颜色设置函数                                                    |
   //+------------------------------------------------------------------+
   void SetCandleColors(int rates_total, const double &open[], const double &close[])
   {
      // 获取图表背景色用于空心效果
      color bg_color = (color)ChartGetInteger(0, CHART_COLOR_BACKGROUND);
      
      // 设置上涨K线为红色边框空心效果
      ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, bg_color);         // 上涨K线实体填充颜色（背景色，实现空心效果）
      ChartSetInteger(0, CHART_COLOR_CHART_UP, UpCandleColor);       // 上涨K线边框和影线颜色（使用配置颜色）
      
      // 设置下跌K线为绿色实心效果
      ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, DownCandleColor);   // 下跌K线实体填充颜色（绿色实心）
      ChartSetInteger(0, CHART_COLOR_CHART_DOWN, DownCandleColor);    // 下跌K线边框和影线颜色（绿色）
      
      // 设置平盘K线颜色和去除中间竖线
      ChartSetInteger(0, CHART_COLOR_CHART_LINE, clrNONE);           // 去除K线实体中间的竖线（设为透明）
      
      // 设置K线显示模式为蜡烛图
      ChartSetInteger(0, CHART_MODE, CHART_CANDLES);
      
      // 刷新图表显示
      ChartRedraw(0);
   }

   //+------------------------------------------------------------------+
   void OnDeinit(const int reason)
   {
      // 清理所有创建的对象
      ObjectsDeleteAll(0, 0, OBJ_TEXT);
      
      // 释放MA句柄
      if(ma43_handle != INVALID_HANDLE)
         IndicatorRelease(ma43_handle);
      if(ma98_handle != INVALID_HANDLE)
         IndicatorRelease(ma98_handle);
      if(ma200_handle != INVALID_HANDLE)
         IndicatorRelease(ma200_handle);
      if(ma5_handle != INVALID_HANDLE)
         IndicatorRelease(ma5_handle);
      if(ema144_handle != INVALID_HANDLE)
         IndicatorRelease(ema144_handle);
      
      // 释放ATR句柄
      if(atr_handle != INVALID_HANDLE)
         IndicatorRelease(atr_handle);
   }